package com.atguigu.test.beandefinition;

import com.atguigu.test.po.User;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

/**
 * @author zp
 * @version 1.0
 * @description:  BeanDefinition类的说明：
 * 继承于：AttributeAccessor, BeanMetadataElement
 * AttributeAccessor：实现类属性的增删改查方法
 * BeanMetadataElement：获取对象的操作方法
 * 它的实现抽象类AbstractBeanDefinition：定义了类信息的基本属性 class beanName 等基本的属性
 *
 * 一、RootBeanDefinition– 不能设置parent bean定义
 *  1、一个RootBeanDefinition定义表明它是一个可合并的bean definition：即在spring beanFactory运行期间，
 *  可以返回一个特定的bean。RootBeanDefini tion可以作为一个重要的通用的bean definition 视图。
 *
 *  2、RootBeanDefinition用来在配置阶段进行注册bean definition。然后，
 *  从spring 2.5后，编写注册bean definition有了更好的的方法：GenericBeanDefinition。
 *  GenericBeanDefinition支持动态定义父类依赖，而非硬编码作为root bean definition。
 *
 * 二、ChildBeanDefinition(必须设置parent bean定义,而且必须是通过构造函数指定):
 *  1、是一种bean definition，它可以继承它父类的设置，即ChildBeanDefinition对RootBeanDefinition有一定的依赖关系。
 *  ChildBeanDefinition从父类继承构造参数值，属性值并可以重写父类的方法，同时也可以增加新的属性或者方法。
 *  (类同于java类的继承关系)。若指定初始化方法，销毁方法或者静态工厂方法，ChildBeanDefinition将重写相应父类的设置。
 *  depends on，autowire mode，dependency check，sigleton，lazy init 一般由子类自行设定。
 *
 * 三、GenericBeanDefinition(可以动态设置parent bean定义,也可以不设置parent bean定义):
 *  1、注意：从spring 2.5 开始，提供了一个更好的注册bean definition类GenericBeanDefinition，
 *  它支持动态定义父依赖，方法是GenericBeanDefinition.setParentName(java.lang.String)，
 *  2、GenericBeanDefinition可以有效的替代ChildBeanDefinition的绝大分部使用场合。
 *  GenericBeanDefinition是一站式的标准bean definition，除了具有指定类、
 *  可选的构造参数值和属性参数这些其它bean definition一样的特性外，它还具有通过parenetName属性来灵活设置parent bean definition。
 *  3、通常， GenericBeanDefinition用来注册用户可见的bean definition(可见的bean definition意味着可以在该类bean definition上定义post-processor来对bean进行操作，
 *  甚至为配置parent name做扩展准备)。RootBeanDefinition / ChildBeanDefinition用来预定义具有parent/child关系的bean definition。
 *
 * 四、mergedBeanDefinition(mdb)，一个非常特殊的对象，它不是一个实现类，是RootBeanDefinition的一个对象，
 *  这个对象在Spring扮演了非常重要的角色。其实它就是将所有的BeanDefinition最后都装饰成一个RootBeanDefinition对象(mergedBeanDefinition)，
 *  这个对象继承了双亲Bean的属性(如果有双亲的话)。
 *  除了上面三个实现类，还存在一些基于注解的实现类：
 *  AnnotatedGenericBeanDefinition，ScannedGenericBeanDefinition 扫描注解注册类的信息
 * @date 2022/12/5 23:01
 */
public class MyBeanDefinition {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // BeanDefinitionBuilder 构建 BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .genericBeanDefinition(User.class)
                .addPropertyValue("userName", "constxiong");
        beanFactory.registerBeanDefinition("user1", builder.getBeanDefinition());
        User user = beanFactory.getBean("user1", User.class);
        System.out.println(user);

        //直接 new 的方式，创建 BeanDefinitionBuilder 对象
        RootBeanDefinition beanDefinition = new RootBeanDefinition(User.class);
        //构造参数
        ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
        constructorArgumentValues.addIndexedArgumentValue(0, "user2");
        beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
        beanFactory.registerBeanDefinition("user2", beanDefinition);
        User user2 = beanFactory.getBean("user2", User.class);
        System.out.println(user2);
    }

}
